package com.controller;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.MalformedURLException;
import java.net.URL;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.RenderedWebElement;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.ie.InternetExplorerDriver;

class Konami extends Thread {

	private static int a;
	public static int lastLine;
	public static int lastA;
	public static String outputFolder;
	public static String inputFile;
	public static String report;
	static String URL;
	static long timeBefore;
	static long timeAfter;
	static long whileTime1;
	static long whileTime2;
	
	static String stackTraceStr;
	static String browser;
	WebDriver driver;

	public static String domInitialSource;
	public static String domInitialSource2;
	public static String domAfterArrows;
	public static String domAfterB;
	public static String domAfterA;
	public static int[] indexesList;

	public Konami(int a, int lastLine, String outputFolder, String inputFile, String report, String browser) {
		Konami.a = a;
		System.out.println("First Konami.a =" + Konami.a);
		Konami.lastLine = lastLine;
		Konami.outputFolder = outputFolder;
		Konami.inputFile = inputFile;
		Konami.report = report;
		Konami.browser = browser;
	}

	public void run() {
		createDirectory(outputFolder);
		createFile(report);

		for (int a = Konami.a; a < lastLine; a++) {
			timeBefore = System.currentTimeMillis() / 1000;
			stackTraceStr = null;
			Konami.a = a;
			try {
				System.out.println("-------------------");
				URL = KonamiThread.urls[a].toString(); // get the URL
				writeCurrentURL(URL);
				System.out.println(URL);
				driver = driverToUse(browser);
				driver.get(URL); // open web page
				whileTime1 = System.currentTimeMillis();
				domInitialSource = driver.getPageSource();
				domInitialSource2 = driver.getPageSource();
				whileTime2 = System.currentTimeMillis();
				while(whileTime2 < whileTime1 + 25000){
					domInitialSource2 = driver.getPageSource();
					whileTime2 = System.currentTimeMillis();
					if(domInitialSource.equals(domInitialSource2)){
						continue;
					}
					else{
						System.out.print("BreakAeg: ");
						System.out.println(whileTime2 - whileTime1);
						break;
					}
				}
				if(domInitialSource.equals(domInitialSource2)){
					WebElement element = driver.findElement(By.xpath("*"));
					System.out.println("Element on: " + element);
					typeArrows(element);
					domAfterArrows = driver.getPageSource(); 
					if (domAfterArrows.equals(domInitialSource)) {
						System.out.println(a + " Arrows do not change DOM");
						try
						{
							Thread.sleep(2000); // do nothing for 2000 miliseconds
						}
						catch(InterruptedException e)
						{
							e.printStackTrace();
						}
						element.sendKeys("b");
						domAfterB = driver.getPageSource();
						if (domAfterB.equals(domInitialSource)) {
							System.out.println(a + " B does not change DOM");
							try
							{
								Thread.sleep(2000); // do nothing for 1000 miliseconds (1 second)
							}
							catch(InterruptedException e)
							{
								e.printStackTrace();
							}
							element.sendKeys("a");
							domAfterA = driver.getPageSource();
							if (domAfterA.equals(domInitialSource)) {
								System.out.println(a + " Konami Code not found!");
								writeDOM(domInitialSource, "noCode");
								timeAfter = System.currentTimeMillis() / 1000;
								writeReport(0); // 0 means code was not found
								driver.quit();
							} else {
								System.out.println(a + " Possible Konami Code detected!!!");
								writeDOM(domInitialSource, "before");
								writeDOM(domAfterA, "afterA");
								timeAfter = System.currentTimeMillis() / 1000;
								writeReport(3); // 3 means possible code was found!

								driver.quit();
							}
						} else {
							System.out.println(a+ " Cannot Detect Konami Code, because pressing B changes DOM!");
							writeDOM(domInitialSource, "before");
							writeDOM(domAfterB, "afterB");
							timeAfter = System.currentTimeMillis() / 1000;
							writeReport(2); // 2 means code cannot be found, because // pressing B changes DOM

							driver.quit();
						}
					} else {
						System.out.println(a + " Cannot Detect Konami Code, because pressing arrow keys changes DOM!");

						writeDOM(domInitialSource, "before");
						writeDOM(domAfterArrows, "afterArrows");
						timeAfter = System.currentTimeMillis() / 1000;
						writeReport(1); // 1 means code cannot be found, because // arrow keys change DOM

						driver.quit();
					}
				}else{
					System.out.println(a + " Cannot Detect Konami Code, because DOM is changing automatically!");
					System.out.println(whileTime2 - whileTime1);
					writeDOM(domInitialSource2, "before");
					writeDOM(domInitialSource, "afterWaiting");
					timeAfter = System.currentTimeMillis() / 1000;
					writeReport(7); // 7 means code cannot be found, because DOM is changing automatically

					driver.quit();
				}
			} catch (Exception ex) {
				StringWriter writerStr = new StringWriter();
				PrintWriter myPrinter = new PrintWriter(writerStr);
				ex.printStackTrace(myPrinter);
				stackTraceStr = writerStr.toString();
				stackTraceStr =  stackTraceStr.replaceAll("\\r|\\n"," ");
				System.out.println("This is the stack: " + stackTraceStr);
				Konami.lastA = a;
				a = 1000000000; // required, or else it won't stop
				//handleException(ex);
				interrupt();
			}
		}
		writeDOM(domInitialSource, "Exeption");
		System.out.println(a + " Exception!");
		timeAfter = System.currentTimeMillis() / 1000;
		writeReport(4); // 4 means an exception occured
		Konami.lastA = a;

		driver.quit();
	}


	public static void handleException(Exception ex){

	}

	public static void writeFile(String fileName, String content, Boolean append) {

		try {
			FileWriter fw = new FileWriter(fileName, append);
			fw.write(content);
			fw.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void typeKonami(WebElement element) {
		element.sendKeys(Keys.ARROW_UP, Keys.ARROW_UP, Keys.ARROW_DOWN,
				Keys.ARROW_DOWN, Keys.ARROW_LEFT, Keys.ARROW_RIGHT,
				Keys.ARROW_LEFT, Keys.ARROW_RIGHT, "b", "a");
	}

	public static void typeArrows(WebElement element) {
		element.sendKeys(Keys.ARROW_UP, Keys.ARROW_UP, Keys.ARROW_DOWN,
				Keys.ARROW_DOWN, Keys.ARROW_LEFT, Keys.ARROW_RIGHT,
				Keys.ARROW_LEFT, Keys.ARROW_RIGHT);
	}

	public static String readFile(File file) {
		StringBuffer contents = new StringBuffer();
		BufferedReader reader = null;
		try {
			reader = new BufferedReader(new FileReader(file));
			String text = null;
			while ((text = reader.readLine()) != null) {
				contents.append(text + "\n");
			}
			reader.close();
			return contents.toString();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return "";
	}

	public static URL[] readURL(File fileName) throws MalformedURLException {
		String content = readFile(fileName);
		String[] lines = content.split("\n");
		URL[] urls = new URL[lines.length];

		for (int i = 0; i < lines.length; i++) {

			String[] values = lines[i].split(",");
			urls[i] = new URL(values[1]);
		}
		return urls;
	}

	public static URL[] readURLs(String inputFile) {
		URL[] urls = null;
		try {
			urls = Konami.readURL(new File(inputFile));
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}
		return urls;
	}

	public static void writeReport(int entryType) {
		//entryType: 0 NoCode, 1 Arrows change DOM , 2 Pressing B changes DOM , 3 Possible Code Detected, 4 Exception, 5 Timeout
		indexesList = readIndexes(inputFile);
		writeFile(report, a + "," + URL + "," + indexesList[a] +","+ entryType + "," + (whileTime2 - whileTime1) + ","
				+ timeBefore + "," + timeAfter + "," + '"'+stackTraceStr +'"'+ "\r\n", true);
	}

	public static void writeDOM(String source, String fileName) {
		writeFile(outputFolder + a + " " + URL.substring(7) + " " + fileName + ".html",
				source, false);
	}

	public static void writeCurrentURL(String URL) {
		writeFile(outputFolder + "temp",
				URL, false);
	}

	public void createDirectory(String outputDirectory){
		try{
			boolean success = (new File(outputDirectory)).mkdir();
			if (success) {
				System.out.println("Directory: " + outputDirectory + " created");
			}    
		}catch (Exception e){//Catch exception if any
			System.err.println("Error: " + e.getMessage());
		}
	}
	public void createFile(String fileName){
		File file = new File(fileName);
		boolean blnCreated = false;		
		try{
			blnCreated = file.createNewFile();
		}catch(IOException ioe){
			System.out.println("Error while creating a new empty file :" + ioe);
		}
		System.out.println("Was file " + file.getPath() + " created ? : " + blnCreated);
	}
	public WebDriver driverToUse(String browser){
		if(browser.equals("iexplore")){
			driver = new InternetExplorerDriver(); 
		}else{
			if(browser.equals("firefox")){
				driver = new FirefoxDriver();
			}else{
				if(browser.equals("chrome")){
					driver = new ChromeDriver();
				}else{
					System.out.println("Please enter iexlpore, firefox or chrome as the browser type");
					driver = null;
				}
			}

		}
		return driver;
	}
	
	public static int[] readIndex(File fileName){
		String content = readFile(fileName);
		String[] lines = content.split("\n");
		int[] indexes = new int[lines.length];

		for (int i = 0; i < lines.length; i++) {
			String[] values = lines[i].split(",");
			indexes[i] = Integer.parseInt(values[0]);
		}
		return indexes;
	}
	
	public static int[] readIndexes(String inputFile){
		int[] indexes = null;
		indexes = readIndex(new File(inputFile));
		return indexes;
	}
}
